/*
 * @copyright fxsen <br/>
 * @date 2022/4/2 18:47 <br/>
 * @email <a href="mailto:fxsen@foxmail.com">
 * @author fxsen
 */
package com.fxsen.commons.core.base.common;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 页对象. 包含当前页数据及分页信息如总记录数.
 * @author fxsen
 * @date 2022/4/2 18:47
 * @email <a href="mailto:fxsen@foxmail.com">
 */
public class Page<T> implements IPage<T> {
    /**
     * 默认每页的记录数
     */
    private static int DEFAULT_PAGE_SIZE = 20;
    private int pageSize = DEFAULT_PAGE_SIZE; // 每页的记录数
    private Object data; // 当前页中存放的记录,类型一般为List
    private long totalCount; // 总记录数
    //总页数
    private long totalPage;
    private int pageNo;
    //asc或desc
    private String sord;
    //排序字段的字段名称,驼峰
    private String sidx;
    //	//查询条件
//	private List<Operation> operations = new ArrayList<Operation>();
    private String condition;

    /**
     * 查询数据列表
     */
    private List<T> records = Collections.emptyList();
    private List<OrderItem> orders = new ArrayList<>();
    /**
     * 构造方法，只构造空页.
     */
    public Page() {
        this(0, 0, DEFAULT_PAGE_SIZE, new ArrayList());
    }
    public Page(int pageNo, int pageSize) {
        this(pageNo, 0, pageSize, new ArrayList());
    }

    /**
     * 默认构造方法.
     *            本页数据在数据库中的起始位置
     * @param totalSize
     *            数据库中总记录条数
     * @param pageSize
     *            本页容量
     * @param data
     *            本页包含的数据
     */
    public Page(int pageNo, long totalSize, int pageSize, Object data) {
        this.pageSize = pageSize;
        this.totalCount = totalSize;
        this.data = data;
        this.pageNo = pageNo;
    }

    /**
     * 构造方法（每页记录条数）
     * @param pageSize
     */
    public Page(int pageSize) {
        this(1, 0, pageSize, new ArrayList());
    }

    /**
     * 设置当前页中存放的记录,类型一般为List
     * @param data
     */
    public void setData(Object data) {
        this.data = data;
    }

    /**
     * 取总记录数.
     */
    public long getTotalCount() {
        return this.totalCount;
    }

    /**
     * 取总页数.
     */
    public long getTotalPage() {
        if(totalCount /pageSize == 0){
            return 1;
        }
        if (totalCount % pageSize == 0)
            return totalCount / pageSize;
        else
            return totalCount / pageSize + 1;
    }

    /**
     * 取每页数据容量.
     */
    public int getPageSize() {
        return pageSize;
    }

    public Object getData() {
        return data;
    }

    /**
     * @see Object#toString()
     */
    @Override
    public String toString() {
        return new ToStringBuilder(this).append("totalPageCount",
                this.getTotalPage()).append("pageSize", this.pageSize)
                .append("result", this.getData()).append("totalCount",
                        this.totalCount).append("currentPageNo",
                        this.getPageNo()).toString();
    }
    /**
     * 设置总记录数
     * @param totalCount
     */
    public void setTotalCount(long totalCount) {
        this.totalCount = totalCount;
    }



    public int getPageNo() {
        return pageNo;
    }

    public void setPageNo(int pageNo) {
        this.pageNo = pageNo;
    }
    public String getSord() {
        return sord;
    }

    public void setSord(String sord) {
        this.sord = sord;
    }

    public String getSidx() {
        return sidx;
    }

    public void setSidx(String sidx) {
        this.sidx = sidx;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

//	public List<Operation> getOperations() {
//		return operations;
//	}
//
//	public void setOperations(List<Operation> operations) {
//		this.operations = operations;
//	}


    public void setTotalPage(long totalPage) {
        this.totalPage = totalPage;
    }

    /**
     * 获取condition
     * @return condition condition
     */
    public String getCondition() {
        return condition;
    }


    /**
     * 设置condition
     * @param condition condition
     */
    public void setCondition(String condition) {
        this.condition = condition;
    }

    /**
     * 解析json为Page对象
     * @param json
     * @return
     */
    public Page<T> parseJson(String json) {
        Page<T> page = new Page<T>();
        JSONObject jsonObj = JSON.parseObject(json);
        page.setPageNo(jsonObj.getIntValue("pageNo"));
        page.setPageSize(jsonObj.getIntValue("pageSize"));
        page.setSidx(jsonObj.getString("sidx"));
        page.setSord(jsonObj.getString("sord"));
        return page;
    }

    public QueryWrapper<T> parseQueryWrapper() {
        QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
        if(StringUtils.isNotEmpty(this.getSidx())) {
            queryWrapper.orderBy(true, !"desc".equals(this.getSord()), this.getSidx());
        }
        String conditionJson = this.getCondition();
        if (StringUtils.isNotEmpty(conditionJson)) {
            List<ConditionVo> conditionList = JSON.parseArray(conditionJson, ConditionVo.class);
            if (CollectionUtil.isNotEmpty(conditionList)) {
                for (ConditionVo conditionVo : conditionList) {
                    String column = conditionVo.getColumn();
                    switch (conditionVo.getType()) {
                        case "eq":
                            queryWrapper.eq(getUnderScope(column), conditionVo.getValue());
                            break;
                        case "ne":
                            queryWrapper.ne(getUnderScope(column), conditionVo.getValue());
                            break;
                        case "like":
                            String[] columnSplit = column.split(",");
                            if(columnSplit.length > 0) {
                                Consumer<QueryWrapper<T>> consumer = qw -> {
                                    for (int i = 0; i < columnSplit.length; i++) {
                                        String camelCaseSourceStr = columnSplit[i];
                                        qw.like(true,getUnderScope(camelCaseSourceStr), conditionVo.getValue()).or();
                                    }
                                };
                                queryWrapper.and(consumer);
                            }
                            break;
                        case "leftlike":
                            queryWrapper.likeLeft(getUnderScope(column), conditionVo.getValue());
                            break;
                        case "rightlike":
                            queryWrapper.likeRight(getUnderScope(column), conditionVo.getValue());
                            break;
                        case "notlike":
                            queryWrapper.notLike(getUnderScope(column), conditionVo.getValue());
                            break;
                        case "gt":
                            queryWrapper.gt(getUnderScope(column), conditionVo.getValue());
                            break;
                        case "lt":
                            queryWrapper.lt(getUnderScope(column), conditionVo.getValue());
                            break;
                        case "ge":
                            queryWrapper.ge(getUnderScope(column), conditionVo.getValue());
                            break;
                        case "le":
                            queryWrapper.le(getUnderScope(column), conditionVo.getValue());
                            break;
                        default:
                            break;
                    }
                }
            }
        }
        return queryWrapper;
    }

    @Override
    public List<OrderItem> orders() {
        return this.orders;
    }

    @Override
    public List<T> getRecords() {
        return this.records;
    }

    @Override
    public Page<T> setRecords(List<T> records) {
        this.records = records;
        return this;
    }

    @Override
    public long getTotal() {
        return totalCount;
    }

    @Override
    public IPage<T> setTotal(long total) {
        totalCount = total;
        return this;
    }

    @Override
    public long getSize() {
        // TODO Auto-generated method stub
        return pageSize;
    }

    @Override
    public IPage<T> setSize(long size) {
        String s = size + "";
        this.pageSize = Integer.parseInt(s);
        return this;
    }

    @Override
    public long getCurrent() {
        return pageNo;
    }

    @Override
    public IPage<T> setCurrent(long current) {
        String s = current + "";
        pageNo = Integer.parseInt(s);
        return this;
    }
    private static String getUnderScope(String camelCaseSourceStr) {
        String[] str = camelCaseSourceStr.split("\\.");
        StringBuffer sb = new StringBuffer();
        for (int k = 0; k < str.length; k++) {
            if (org.springframework.util.StringUtils.isEmpty(str[k])) {
                return "";
            }
            Pattern p = Pattern.compile("[A-Z]");
            StringBuilder stringBuilder = new StringBuilder(str[k]);
            Matcher mc = p.matcher(str[k]);
            int i = 0;
            while (mc.find()) {
                int j = mc.start(), t = mc.end();
                if(j == 0){//跳过首字符是大写的情况
                    continue;
                }
                stringBuilder.replace(j + i, t + i, "_" + mc.group().toLowerCase());
                i++;
            }
            if ("_".equals(stringBuilder.charAt(0))) {
                stringBuilder.deleteCharAt(0);
            }
            sb.append(stringBuilder.toString().toUpperCase());
            if(k < str.length - 1) {
                sb.append(".");
            }
        }
        return sb.toString();
    }
}
